#include "spu.h"
#include "list_operate.h"
#include <semaphore.h>

#define   max_size    1024
Client_Node *head;  //客户端头结点
int sockfd;         //处理链接的套接字
sem_t sem;          //定义信号量
char menu_buff[max_size];   //用于存储所有客户端发送来的数据
int current_client; //当前发消息的客户端套接字


/*客户端线程*/
void *client_fun(void *arg)
{
    int connfd = (long int)arg;
    //接受客户端数据缓冲区
    char buff[max_size];
    memset(buff, 0, sizeof(buff));
    
    //欢迎语，发送给客户端
    char sd[] = "-----welcome to my server!-----";
    send(connfd, sd, sizeof(sd), 0);

    for(;;)
    {
        int recv = read(connfd, buff, sizeof(buff));
        if(recv > 0){
            current_client = connfd;
            //在数据前面加上客户端名字,将客户端发送数据拷贝到menu_buff
            sprintf(menu_buff, "%d:%s",current_client, buff);
            // printf("I am %d, recieve data = %s\n", connfd, buff);
            sem_post(&sem);  //信号量+1
            memset(buff, 0, sizeof(buff));
        }
        //如果返回是0，说明链接可能断开
        if(recv == 0){
            if(0 == close(connfd))  //关闭链接
                printf("I am %d, closed\n", connfd);
            del_list_client(head, connfd);  //删除用户结点
            //退出线程
            pthread_exit(NULL);
        }
    }   
}

/*菜单线程*/
void * menu_thread(void *arg)
{
    for(;;)
    {
        //等待信号量大于0，等到后对信号量”减1“
        if(0 == sem_wait(&sem))
        {
            //转发数据到其他客户端
            Client_Node *p = head->next;
            while(p != NULL)
            {
                //除去当前发消息的客户端
                if(p->connfd != current_client){
                    send(p->connfd, menu_buff, sizeof(menu_buff), 0);
                }
                p = p->next;
            }
            memset(menu_buff, 0, sizeof(menu_buff));
        }

    }
}

/*检测到ctrl+c的信号函数*/
void close_fun()
{
    close(sockfd);
    printf("stop tcpserver\n");
    exit(0);
}

int main()
{
    signal(SIGINT, close_fun);

    /*初始化信号量*/
    sem_init(&sem, 1, 0);

    /*1.创建套接字*/
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1){
        printf("create socket failed!\n");
        return 0;
    }

    /*2.绑定IP和端口,分配地址给套接字*/
    struct sockaddr_in addr;
    addr.sin_port = htons(6666);  //函数将无符号短整数hostshort从主机字节顺序转换为网络字节顺序。
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY:0.0.0.0，可以泛指本机的所有IP（多个网卡）
                                              //而127.0.0.1只能是服务器和客户端都在本机上才可以
    int res;
    res = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
    if(res == -1){
        printf("bind failed!\n");
        return 0;
    }

    /*3.监听链接请求*/
    if(listen(sockfd, 100) == -1){
        printf("listen failed!\n");
        return 0;
    }
    printf("start accept\n");

    /*申请头结点*/
    head = (Client_Node *)malloc(sizeof(Client_Node));
    head->next = NULL;

    /*创建菜单线程*/
    pthread_t menu_thread_id;
    pthread_create(&menu_thread_id, NULL, menu_thread, NULL);
    
    /*4.循环等待客户端链接*/ 
    /*主线程接收客户端链接请求*/
    while(1){
        long int connfd;
        connfd = accept(sockfd, NULL, NULL);
        
        if(connfd != -1){ 
            printf("a client connect!, connfd = %ld\n",connfd);
            /*向链表中添加新用户结点*/
            add_list_client(head, connfd);
            printf("current all client are:\n");
            Client_Node *p = head->next;
            for( ; p != NULL ; )
            {
                printf("--- %d\n",p->connfd);
                p = p->next;
            }
            
            /*创建新线程处理客户端数据*/
            pthread_t thread_id;
            pthread_create(&thread_id, NULL, client_fun, (void*)connfd);
        }
    }
    
    return 0;
}
